package com.carful.xigua.modules.common.util;

import com.google.gson.Gson;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.gson.io.GsonSerializer;
import io.jsonwebtoken.security.Keys;
import jakarta.servlet.http.HttpServletRequest;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.crypto.SecretKey;
import java.util.Date;
import java.util.Map;

@Component
@Data
@Slf4j
public class JwtUtils {

    @Value("${jwt.data.secret:$2a$10$LxyFdGk6Tp13Wy4/dW9N..eEFHVo.qfmjtNkgUf1DhmEc5K0jE1WK}")
    private String secret;//秘钥

    @Value("${jwt.data.expiration:86400}")
    private Long expiration = 60L * 60 * 24; //过期时间 秒

    @Value("${jwt.data.tokenHeader:token}")
    private String tokenHeader = "token"; // token 存放请求头key

    @Value("${jwt.data.AccessTokenHeader:Access-Control-Expose-Headers}")
    private String AccessTokenHeader = "Access-Control-Expose-Headers";

    private final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

    private final GsonSerializer<Map<String, ?>> gsonSerializer = new GsonSerializer<>(new Gson());

    private final JwtTokenBlacklist jwtTokenBlacklist;

    @Autowired
    public JwtUtils(JwtTokenBlacklist jwtTokenBlacklist) {
        this.jwtTokenBlacklist = jwtTokenBlacklist;
    }

    public SecretKey getKey() {
        return Keys.hmacShaKeyFor(secret.getBytes());
    }

    //根据负载生成jwt token
    private String createToken(Map<String, Object> claims) {
        //jjwt构建jwt builder
        //设置信息，过期时间，signnature
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(expirationDate())
                .signWith(getKey(), signatureAlgorithm)
                .serializeToJsonWith(gsonSerializer)
                .compact();
    }

    // 生成 JWT 令牌
    public String generateToken(String userDetails) {
        return Jwts.builder()
                .setSubject(userDetails)
                .setIssuedAt(new Date())
                .setExpiration(expirationDate())
                .signWith(getKey(), signatureAlgorithm)
                .serializeToJsonWith(gsonSerializer)
                .compact();
    }

    // 从请求中获取 JWT 令牌
    public String getTokenFromRequest(HttpServletRequest request) {
        String bearerToken = request.getHeader(tokenHeader);
        if (StringUtils.hasText(bearerToken)) {
            return bearerToken;
        }
        return null;
    }

    //根据token获取用户名
    public String getUserFromToken(String token) {
        String user = "";
        try {
            Claims claims = getClaimsFromToken(token);
            user = claims.getSubject();
        } catch (Exception e) {
            log.info("error:{}", "用户名未能获取 from token");
        }
        return user;
    }

    public String getUsernameFromToken(String token) {
        String user = "";
        try {
            Claims claims = getClaimsFromToken(token);
            user = claims.getSubject();
        } catch (Exception e) {
            log.info("error:{}", "用户名未能获取 from token");
        }
        return user;
    }

    //从token中获取荷载
    private Claims getClaimsFromToken(String token) {
        Claims claims = null;
        try {
            claims = Jwts.parserBuilder()
                    .setSigningKey(getKey())
                    .build()
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return claims;
    }

    //生成token失效时间
    private Date expirationDate() {
        //失效时间为：系统当前毫秒数+我们设置的时间（s）*1000=》毫秒
        //其实就是未来7天
        return new Date(System.currentTimeMillis() + expiration * 1000);
    }

    //判断token是否有效
    public boolean validateToken(String token, UserDetails userDetails) {
        //判断token是否过期
        //判断token是否和userDetails中的一致
        //我们要做的 是先获取用户名
        return isTokenExpired(token) && !isTokenBlacklisted(token) && getUsernameFromToken(token).equals(userDetails.getUsername());
    }

    // 检查 JWT 令牌是否在黑名单中
    public boolean isTokenBlacklisted(String token) {
        return jwtTokenBlacklist.isTokenBlacklisted(token);
    }

    //判断token、是否失效
    //失效返回true
    public boolean isTokenExpired(String token) {
        Date expiredDate = getExpiredDateFromToken(token);
        return !expiredDate.before(new Date());
    }

    //从荷载中获取时间
    private Date getExpiredDateFromToken(String token) {
        Claims claims = getClaimsFromToken(token);
        return claims.getExpiration();
    }

    // 将 JWT 令牌设置为无效
    public void invalidateToken(String token) {
        jwtTokenBlacklist.addTokenToBlacklist(token);
    }

    //判断token是否可以被刷新
    //过期（销毁）就可以
    public boolean canBeRefreshed(String token){
        return isTokenExpired(token);
    }

    //刷新token
    public String refreshToken(String token){
        Claims claims = getClaimsFromToken(token);
        //修改为当前时间
        claims.setIssuedAt(new Date());
        return createToken(claims);
    }

}
